import bpy
import numpy as np


from 节点.全局控制.Node.节点和插座基类 import bl_UpdateNode
from 节点.全局控制.Node.插座 import bl_插座基类

import engine.initLIB.load_dll as engineLib
import ctypes
import 节点.Core.bl_UI配色 as 配色









E_类型枚举_坐标系轴向 = [
	("TYPE_右手转左手", "右手转左手", "", 0),
	("TYPE_左手转右手", "左手转右手", "", 1),
	("TYPE_逆转", "逆转", "", 2),
]


E_类型枚举_轴向 = [
	("TYPE_轴向X", "X", "", 0),
	("TYPE_轴向Y", "Y", "", 1),
	("TYPE_轴向Z", "Z", "", 2),
]







E_运算类型枚举 = [
	("TYPE_加法", "+", "", 0),
	("TYPE_减法", "-", "", 1),
	("TYPE_乘法", "*", "", 2),
	("TYPE_除法", "/", "", 3),

	("TYPE_取余", "%", "", 4),
	("TYPE_取负", "取负", "取负", 5),

	("TYPE_取反", "！", "", 6),
	("TYPE_左移", "<<", "", 7),
	("TYPE_右移", ">>", "", 8),

	("TYPE_累加", "+=", "", 9),
	("TYPE_累减", "-=", "", 10),

	("TYPE_按位与", "&", "&", 11),
	("TYPE_按位或", "|", "|", 12),
	("TYPE_按异或", "^", "^", 13),

	("TYPE_平方", "**", "**", 14),
	("TYPE_点积", "点积", "点积", 15),
	("TYPE_叉积", "叉积", "叉积", 16),
	("TYPE_步进", "步进", "步进", 17),
]






E_变换类型枚举 = [
	("location", "位置", "", 0),
	("rotation_euler", "旋转", "", 1),
	("scale", "缩放", "", 2),
]






g_添加链接节点 = None
g_当前更新节点 = {}
def f_当前添加链接的节点():
	global g_添加链接节点
	#print('g_添加链接节点 == ', g_添加链接节点)
	if len(g_添加链接节点):
		return g_添加链接节点[0]
	else:
		return None
def f_当前添加链接的节点添加(data):
	global g_添加链接节点
	g_添加链接节点.append(data)
	#print('f_当前添加链接的节点添加 == ', g_添加链接节点)

def f_当前添加链接的节点清空():
	global g_添加链接节点
	#g_添加链接节点 = []

class C_SN_基类(bpy.types.Node, object):
	bl_label = 'C_SN_基类'
	def f_init(self, 子类):
		self.inputs.new('C_NodeSocket_传递', name='_>')
		self.outputs.new('C_NodeSocket_传递', name='_<')
		self.m_是否要更新 = True
	@classmethod
	def poll(self, node_tree):
		return True
	def f_input插座Update(self, input插座, 上层Output=None):
		if input插座.name == '_>':
			if 上层Output and 上层Output.f_getData() == False:
				return
		self.f_pushUpdate()
	def f_update(self, 是否向下传递=False, input插座=None):
		self.m_是否要更新 = False
		bl_UpdateNode.f_递归到子节点Update(self.outputs, 是否向下传递)
		for input in self.inputs :
			input.f_pushUpdate()
	def f_pushUpdate(self):
		self.m_是否要更新 = True
	def f_标记为已更新(self):
		self.m_是否要更新 = False
	def f_is未更新(self):
		return self.m_是否要更新
	def f_is以更新(self):
		if self.m_是否要更新 :
			return False
		return True
	def f_is强制Update(self):
		return False
	def f_is自动Update(self):
		return True
	def f_toCPP(self):
		pass









class C_插座列表_UL_example(bpy.types.UIList):
	def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
		ob = data
		槽 = item
		#if item.bl_idname == 'C_ShaderNodeTree':
		layout.prop(item, "name", icon_value=icon)

class C_NODE_MENU_移除插座(bpy.types.Operator):
	bl_idname = 'node.remove_socket'
	bl_label = '移除插座'
	bl_options = {'REGISTER', 'UNDO'}
	m_TreeName = bpy.props.StringProperty()
	m_NodeName = bpy.props.StringProperty()
	m_SocketLoc = bpy.props.IntProperty()
	#m_SocketName = bpy.props.StringProperty()
	m_输出 = bpy.props.BoolProperty()
	def execute(self, context):
		#断开插座
		node = bpy.data.node_groups[self.m_TreeName].nodes[self.m_NodeName]
		tree = node.f_get树()
		m_SocketName = ''
		if self.m_输出 :
			socket = node.outputs[self.m_SocketLoc]
			m_SocketName = socket.identifier
			node.outputs.remove(socket)
			#移除包内插座
			Group_Output = tree.nodes['Group Output']
			bl_插座基类.f_移除插座(Group_Output.inputs, m_SocketName)
		else:
			socket = node.inputs[self.m_SocketLoc]
			m_SocketName = socket.identifier
			node.inputs.remove(socket)
			#移除包内插座
			Group_Input = tree.nodes['Group Input']
			bl_插座基类.f_移除插座(Group_Input.outputs, m_SocketName)
			
			
		data = [list(m_SocketName), int(self.m_输出)]
		engineLib.flexCAPI.f_bl_移除节点插座(ctypes.c_wchar_p(self.m_TreeName), ctypes.c_wchar_p(self.m_NodeName), ctypes.py_object(data))
		return {'FINISHED'}



class C_NODE_MENU_移动插座(bpy.types.Operator):
	bl_idname = 'node.edit_socket_move'
	bl_label = '上移插座'
	bl_options = {'REGISTER', 'UNDO'}
	m_TreeName = bpy.props.StringProperty()
	m_NodeName = bpy.props.StringProperty()
	m_SocketLoc = bpy.props.IntProperty()
	m_输出 = bpy.props.BoolProperty()
	m_步进 = bpy.props.IntProperty()
	def execute(self, context):
		if self.m_SocketLoc <= 1 and self.m_步进 < 0: return {'FINISHED'}
		
		node = bpy.data.node_groups[self.m_TreeName].nodes[self.m_NodeName]
		if self.m_输出:
			socket = node.outputs
		else:
			socket = node.inputs
		socket.move(self.m_SocketLoc, self.m_SocketLoc+self.m_步进)

		tree = node.f_get树()
		if tree :
			
			if self.m_输出:
				sanNode = tree.nodes['Group Output']
				Group_socket = sanNode.inputs
			else:
				sanNode = tree.nodes['Group Input']
				Group_socket = sanNode.outputs

			Group_socket.move(self.m_SocketLoc, self.m_SocketLoc+self.m_步进)

			engineLib.flexCAPI.f_移动插座(	ctypes.c_wchar_p(node.id_data.name), 
											ctypes.c_wchar_p(node.name), 
											ctypes.c_int(self.m_输出), 
											ctypes.c_int(self.m_步进), 
											ctypes.c_int(self.m_SocketLoc))
		return {'FINISHED'}




class C_NODE_MENU_创建插座(bpy.types.Operator):
	bl_idname = 'node.create_socket'
	bl_label = '创建插座'
	bl_options = {'REGISTER', 'UNDO'}
	m_TreeName = bpy.props.StringProperty()
	m_NodeName = bpy.props.StringProperty()
	m_输出 = bpy.props.BoolProperty()

	#m_插座类型 = bpy.props.EnumProperty(items=bl_插座基类.E_数值插座类型枚举, name="类型", default="C_Socket_F32")
	#m_插座维度 = bpy.props.EnumProperty(items=bl_插座基类.E_创建插座维度枚举, name="维度", default="TYPE_插座维度_0")
	def execute(self, context):
		m_插座类型 = context.scene.m_插座类型
		m_插座维度 = context.scene.m_插座维度
		维度 = 0
		if m_插座维度 == 'TYPE_插座维度_1':
			维度 = 1
		elif m_插座维度 == 'TYPE_插座维度_2':
			维度 = 2
		elif m_插座维度 == 'TYPE_插座维度_3':
			维度 = 3
		elif m_插座维度 == 'TYPE_插座维度_4':
			维度 = 4

		node = bpy.data.node_groups[self.m_TreeName].nodes[self.m_NodeName]
		socket = bl_插座基类.f_创建插座(node, m_插座类型, 维度, self.m_输出, None)
		
		data = []
		data.append(list(socket.bl_idname))
		data.append(list(socket.identifier))
		#data.append(维度)
		data.append(int(self.m_输出))

		if self.m_输出 :
			data.append(int(len(node.outputs)))
		else:
			data.append(int(len(node.inputs)))
			
		#print('socket type', data)
		engineLib.flexCAPI.f_bl_创建节点插座(ctypes.c_wchar_p(self.m_TreeName), ctypes.c_wchar_p(self.m_NodeName), ctypes.py_object(data))
		

		#内部输入输出节点插座
		tree = node.f_get树()
		if tree :
			if self.m_输出 :
				GroupOutput = tree.nodes['Group Output']
				socket = bl_插座基类.f_创建插座(GroupOutput, m_插座类型, 维度, False, socket.identifier)
				
			else:
				GroupInput = tree.nodes['Group Input']
				socket = bl_插座基类.f_创建插座(GroupInput, m_插座类型, 维度, True, socket.identifier)
			

		return {'FINISHED'}
		


def f_绘制节点插座修改面板(node, layout):
	in布局 = layout.box()
	col = in布局.column()

	#col.template_list("C_插座列表_UL_example", "", node, "inputs", node.inputs, "_>", rows=4)
	index = 0
	for socket in node.inputs[1:]:
		index += 1

		row = col.row()
		row.prop( socket, 'name', text=socket.identifier)
		
		item = row.operator('node.remove_socket', icon='PANEL_CLOSE')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		#item.m_SocketName = socket.identifier
		item.m_输出 = False


		item = row.operator('node.edit_socket_move', icon='TRIA_UP', text='')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		item.m_步进 = -1
		item.m_输出 = False
		item = row.operator('node.edit_socket_move', icon='TRIA_DOWN', text='')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		item.m_步进 = 1
		item.m_输出 = False

		
	row = col.row()
	
	item = row.operator('node.create_socket', text='创建输入插座', icon='ADD')
	item.m_TreeName = node.id_data.name
	item.m_NodeName = node.name
	item.m_输出 = False
	
	row.prop(bpy.context.scene, 'm_插座类型')
	row.prop(bpy.context.scene, 'm_插座维度')
	

	out布局 = layout.box()
	col = out布局.column()
	index = 0
	for socket in node.outputs[1:]:
		index += 1
		
		row = col.row()
		row.prop( socket, 'name', text=socket.identifier)
		
		item = row.operator('node.remove_socket', icon='PANEL_CLOSE', text='')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		item.m_输出 = True


		item = row.operator('node.edit_socket_move', icon='TRIA_UP', text='')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		item.m_步进 = -1
		item.m_输出 = True
		item = row.operator('node.edit_socket_move', icon='TRIA_DOWN', text='')
		item.m_TreeName = node.id_data.name
		item.m_NodeName = node.name
		item.m_SocketLoc = index
		item.m_步进 = 1
		item.m_输出 = True

		

	row = col.row()
	item = row.operator('node.create_socket', text='创建输出插座', icon='ADD')
	item.m_TreeName = node.id_data.name
	item.m_NodeName = node.name
	item.m_输出 = True
	row.prop(bpy.context.scene, 'm_插座类型')
	row.prop(bpy.context.scene, 'm_插座维度')







class C_创建节点插座Menu(bpy.types.Menu):
	bl_idname = "OBJECT_MT_socketcreator_submenu"
	bl_label = "创建插座"
	
	def draw(self, context):
		layout = self.layout.row()
		layout.popover(panel="C_创建节点插座面板", text="", icon='PLUGIN')
		layout.scale_x = 400
		layout.ui_units_x = 400
		
		
class C_创建节点插座面板(bpy.types.Panel):
	bl_space_type = 'NODE_EDITOR'
	bl_region_type = 'UI'
	bl_label = "创建节点插座"
	def draw(self, context):
		layout = self.layout
		if context.space_data.type == 'NODE_EDITOR':
			g_当前激活节点 = context.active_node
			if g_当前激活节点 : f_绘制节点插座修改面板(g_当前激活节点, layout)

class C_NODE_MENU_弹出节点插座创建菜单(bpy.types.Operator):
	bl_idname = 'node.pop_socket_create_submenu'
	bl_label = '弹出节点插座创建菜单'
	#bl_options = {'REGISTER', 'UNDO'}

	'''def panel_func(self, context):
		layout = self.layout
		if context.space_data.type == 'NODE_EDITOR':
			g_当前激活节点 = context.active_node
			f_绘制节点插座修改面板(g_当前激活节点, layout)'''

		#row = layout.row(align=True)
		#row.menu(C_创建节点插座Menu.__name__, text=C_创建节点插座Menu.bl_label)

	def execute(operator, context):
		bpy.ops.wm.call_menu(name="OBJECT_MT_socketcreator_submenu")
		#layout.popover(panel="C_过滤面板", text="", icon='FILTER')
		return {'FINISHED'}
		





























class C_Node_基类(bpy.types.Node):
	bl_label = 'base node'

	def f_init(self, context, 创建执行阈=True):
		#if 创建执行阈 :
		self.inputs.new('C_Socket_节点流程阀', name='_>')
		self.outputs.new('C_Socket_节点流程阀', name='_<')
		self.m_是否要更新 = False
		self.inputs['_>'].hide = True
		self.outputs['_<'].hide = True

		

		
	@classmethod
	def poll(self, node_tree):
		#print('node node_tree C == ', 'mbt', node_tree, self)
		return True
	
	def draw_buttons_ext(self, context, layout):
		layout.label(text='mbt:' + str( engineLib.flexCAPI.f_node_取节点层级(ctypes.c_wchar_p(self.id_data.name), ctypes.c_wchar_p(self.name)) ))
		#self.draw_buttons(context, layout)
		#绘制专有属性
		if self.bl_static_type == 'GROUP':
			#绘制插座修改
			f_绘制节点插座修改面板(self, layout)
			
	
	def update(self):
		self.m_是否要更新 = True
		engineLib.flexCAPI.f_记录断开链接节点(ctypes.c_wchar_p(self.id_data.name), ctypes.c_wchar_p(self.name))
	#def draw_label(self):
	#	return self.name
	def f_update(self):
		return
	def f_toCPP(self, tree):
		print('node f_toCPP == ', '在父类 err!', self.name)
		pass
	
	def copy(self, node):
		print('node copy == ', 'mbt', self.name)
		self.f_toCPP(self.id_data)

	def free(self):
		engineLib.flexCAPI.f_删除节点(ctypes.c_wchar_p(self.id_data.name), ctypes.c_wchar_p(self.name))
		self.f_release()

	def insert_link(self, link):
		global g_添加链接节点
		if g_添加链接节点 != link:
			engineLib.flexCAPI.f_node_构建链接(ctypes.c_wchar_p(self.id_data.name),
										ctypes.c_wchar_p(link.from_node.name),
										ctypes.c_wchar_p(link.to_node.name),
										ctypes.c_wchar_p(link.from_socket.identifier),
										ctypes.c_wchar_p(link.to_socket.identifier),
										)
			engineLib.flexCAPI.f_标记指定节点需更新(ctypes.c_wchar_p(self.id_data.name), ctypes.c_wchar_p(link.to_node.name));
		g_添加链接节点 = link

		if link.from_node.name != self.name :
			engineLib.flexCAPI.f_记录当前插座变更节点(ctypes.c_wchar_p(self.id_data.name), ctypes.c_wchar_p(self.name))
		#print('insert_link = ', self.name, self.id_data.name, link.to_node.name, link.from_node.name, link)
		


	def poll_instance(self, node_tree):
		print('poll_instance')
	def socket_value_update(self, context):
		print('*********************socket_value_update = ', self.name, self.id_data.name, link)
		
	def f_insert_link(self, link):
		#链向节点的输入插座 = link.to_socket
		#链向的节点 = link.to_node
		engineLib.flexCAPI.f_node_构建链接(ctypes.c_wchar_p(self.id_data.name),
											ctypes.c_wchar_p(link.from_node.name),
											ctypes.c_wchar_p(link.to_node.name),
											ctypes.c_wchar_p(link.from_socket.identifier),
											ctypes.c_wchar_p(link.to_socket.identifier),
											)

		#print('***** f_insert_link = ', self.name, self.id_data.name, link.from_socket.identifier, link.to_socket.identifier)


		
	def f_构建内部链接(self, 链接=None):
		if 链接 :
			self.f_insert_link(链接)
		else :
			for 输出插座 in self.outputs:
				for link in 输出插座.links:
					self.f_insert_link(link)
	
	def f_link_断开(self, 链接=None):
		link = []
		for socket in self.inputs:
			if socket.is_linked == False:
				link.append(True)
			else : link.append(False)
		if len(link):
			pass
		
	def f_release(self):
		pass

	#def f_断开所有插座(self):
	#	engineLib.flexCAPI.f_断开链接节点(ctypes.py_object(data))

	def f_getPyObject(self, tree):
		return ctypes.py_object(tree.nodes[self.name])
	def f_get_节点指针(self, tree):
		return ctypes.py_object(tree.nodes[self.name])




def f_构建内部链接(self):
	for 输出插座 in self.outputs:
		for link in 输出插座.links:
			engineLib.flexCAPI.f_node_构建链接(ctypes.c_wchar_p(self.id_data.name),
												ctypes.c_wchar_p(link.from_node.name),
												ctypes.c_wchar_p(link.to_node.name),
												ctypes.c_wchar_p(link.from_socket.identifier),
												ctypes.c_wchar_p(link.to_socket.identifier),
												)
	



def f_构建双向内部链接(self):
	for 输入插座 in self.inputs:
		for link in 输入插座.links:
			engineLib.flexCAPI.f_node_构建链接(ctypes.c_wchar_p(self.id_data.name),
												ctypes.c_wchar_p(link.from_node.name),
												ctypes.c_wchar_p(link.to_node.name),
												ctypes.c_wchar_p(link.from_socket.identifier),
												ctypes.c_wchar_p(link.to_socket.identifier),
												)
	for 输出插座 in self.outputs:
		for link in 输出插座.links:
			engineLib.flexCAPI.f_node_构建链接(ctypes.c_wchar_p(self.id_data.name),
												ctypes.c_wchar_p(link.from_node.name),
												ctypes.c_wchar_p(link.to_node.name),
												ctypes.c_wchar_p(link.from_socket.identifier),
												ctypes.c_wchar_p(link.to_socket.identifier),
												)



def f_断开需要断开的节点输入插座(treeName):
	#print('f_断开需要断开的节点输入插座 = ', treeName)
	nodes = engineLib.flexCAPI.f_get断开输入链接节点(ctypes.c_wchar_p(treeName))
	#print('断开链接 = node = ', nodes)
	data = []
	for node in nodes:
		是否断开链接 = []
		for socket in node.inputs:
			if socket.is_linked:
				是否断开链接.append(0)
			else:
				是否断开链接.append(1)
		data.append((list(node.name), 是否断开链接))
	#print('f_断开需要断开的节点输入插座 = ', treeName, data)
	engineLib.flexCAPI.f_断开链接节点(ctypes.c_wchar_p(treeName), ctypes.py_object(data))
	
	return len(data)







def f_重定向节点_toCPP(self, node):
	#print('self.id_data.name A = ', self.name)
	#print('self.id_data.name B = ', node.name)
	#print('bpy.data.node_groups B = ', self.nodes)
	#print('bpy.data.node_groups[self.id_data.name].nodes B = ', bpy.data.node_groups[self.id_data.name].nodes)
	data = ctypes.py_object(self.nodes[node.name])
	engineLib.flexCAPI.f_创建重定向节点(ctypes.c_wchar_p(self.name), ctypes.c_wchar_p(node.name), data);










classes = (
	C_SN_基类,

	C_插座列表_UL_example,
	C_NODE_MENU_移除插座,
	C_NODE_MENU_移动插座,
	C_NODE_MENU_创建插座,

	C_创建节点插座Menu,
	C_创建节点插座面板,
	C_NODE_MENU_弹出节点插座创建菜单,

	C_Node_基类,


)







def f_执行代码(self, 全局变量, 文件头=''):
	#self.m_Code.lines[0] = 文件头
	代码 = self.m_Code.as_string() + '\n'
	exec(代码, 全局变量)


def f_插座数据是否独立(self, name, 对象数量):
	data = self.inputs[name].f_getData()
	
	num = len(data)
	#print('数组插座接受非数组数据 or 没有连接')
	是否独立 = False
	if num >= 对象数量:
		是否独立 = True
	else:
		data = data[0]

	return data, 是否独立
	










def f_重新调整插座(m_TreeName, m_NodeName, socket, Out, loc):
	data = []
	data.append(list(socket.bl_idname))
	data.append(list(socket.identifier))
	#data.append(维度)
	data.append(int(Out))
	data.append(int(loc))
	#print('f_重新调整插座 =  *********** socket type', data)
	engineLib.flexCAPI.f_bl_创建节点插座(ctypes.c_wchar_p(m_TreeName), ctypes.c_wchar_p(m_NodeName), ctypes.py_object(data))
	


def f_重新调整节点插座(node, Out):
	if Out :
		sockets = node.outputs
	else:
		sockets = node.inputs
	for i, socket in enumerate(sockets[1:]):
		f_重新调整插座(m_TreeName=node.id_data.name, m_NodeName=node.name, socket=socket, Out=Out, loc=i+1)

	



def f_input插座动态增减(self, 剩余数量, 添加插座类型='', name=''):
	#print('f_input插座动态增减 == ', len(self.inputs), 剩余数量)
	if len(self.inputs) > 剩余数量 :
		for i in range(剩余数量, len(self.inputs)):
			l = self.inputs[-1]
			if l.is_linked == False:
				self.inputs.remove(l)

		self.inputs.new(添加插座类型, name=name+'_'+str(len(self.inputs)))
		node = self.inputs[-1].node
		f_重新调整插座(node.id_data.name, node.name, self.inputs[-1], False, len(self.inputs)-1)

	if self.inputs[-1].is_linked == True:
		self.inputs.new(添加插座类型, name=name+'_'+str(len(self.inputs)))
		node = self.inputs[-1].node
		f_重新调整插座(node.id_data.name, node.name, self.inputs[-1], False, len(self.inputs)-1)




def f_CollectionProperty数量update(value, count):
	差数 = len(value) - count
	
	if 差数 > 0 :
		for i in range(差数):
			value.remove(len(value)-1)
	else:
		差数 = -差数
		for i in range(差数):
			value.add()








def getActiveDepsgraph():
	return bpy.context.evaluated_depsgraph_get()

def getEvaluatedObject(object):
	return object.evaluated_get(getActiveDepsgraph())













def register():
	

	bpy.types.Node.m_是否要更新 = bpy.props.BoolProperty(name='是否要更新', default=False)
	bpy.types.Node.m_Type = bpy.props.StringProperty(name='Type', default='自定义')

	bpy.types.Scene.m_插座类型 = bpy.props.EnumProperty(items=bl_插座基类.E_数值插座类型枚举, name="类型", default="C_Socket_F32")
	bpy.types.Scene.m_插座维度 = bpy.props.EnumProperty(items=bl_插座基类.E_创建插座维度枚举, name="维度", default="TYPE_插座维度_0")

	#bpy.types.Scene.m_全局更新标识 = bpy.props.IntProperty(name='全局更新标识', default=-100000000)

	for c in classes:
		bpy.utils.register_class(c)
		
def unregister():
	for c in classes:
		bpy.utils.unregister_class(c)

	

